home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 January / PCWorld_2003-01_cd.bin / Software / Vyzkuste / rychlokurz / httrack.exe / {app} / src / htsback.c < prev    next >
C/C++ Source or Header  |  2002-11-17  |  97KB  |  2,475 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       backing system (multiple socket download)              */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsback.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htsnet.h"
  43. #include "htsthread.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <time.h>
  48. /* END specific definitions */
  49.  
  50. //#if HTS_WIN
  51. #include "htsftp.h"
  52. #if HTS_USEZLIB
  53. #include "htszlib.h"
  54. #endif
  55. //#endif
  56.  
  57. #if HTS_WIN
  58. #ifndef __cplusplus
  59. // DOS
  60. #include <process.h>    /* _beginthread, _endthread */
  61. #endif
  62. #else
  63. #endif
  64.  
  65. #undef test_flush
  66. #define test_flush if (opt->flush) { if (opt->log) { fflush(opt->log); } if (opt->errlog) { fflush(opt->errlog);  } }
  67.  
  68. #define VT_CLREOL       "\33[K"
  69.  
  70.  
  71. // ---
  72. // routines de backing
  73. // retourne l'index d'un lien dans un tableau de backing
  74. int back_index(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  75.   int i=0;
  76.   int index=-1;
  77.   while( i<back_max ) {
  78.     if (back[i].status>=0)    // rΘception OU prΩt
  79.       if (strfield2(back[i].url_adr,adr)) {
  80.         if (strcmp(back[i].url_fil,fil)==0) {
  81.           if (index==-1)    /* first time we meet, store it */
  82.             index=i;
  83.           else if (strcmp(back[i].url_sav,sav)==0) {  /* oops, check sav too */
  84.             index=i;
  85.             return index;
  86.           }
  87.         }
  88.       }
  89.     i++;
  90.   }
  91.   return index;
  92. }
  93.  
  94. // nombre d'entrΘes libres dans le backing
  95. int back_available(lien_back* back,int back_max) {
  96.   int i;
  97.   int nb=0;
  98.   for(i=0;i<back_max;i++)
  99.     if (back[i].status==-1)     /* libre */
  100.       nb++;
  101.   return nb;
  102. }
  103.  
  104. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  105. LLint back_incache(lien_back* back,int back_max) {
  106.   int i;
  107.   LLint sum=0;
  108.   for(i=0;i<back_max;i++)
  109.     if (back[i].status!=-1)
  110.       if (back[i].r.adr)       // ne comptabilier que les blocs en mΘmoire
  111.         sum+=max(back[i].r.size,back[i].r.totalsize);
  112.   return sum;
  113. }
  114.  
  115. // le lien a-t-il ΘtΘ mis en backing?
  116. HTS_INLINE int back_exist(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  117.   return (back_index(back,back_max,adr,fil,sav)>=0);
  118. }
  119.  
  120. // nombre de sockets en tΓche de fond
  121. int back_nsoc(lien_back* back,int back_max) {
  122.   int n=0;
  123.   int i;
  124.   for(i=0;i<back_max;i++)
  125.     if (back[i].status>0)    // rΘception uniquement
  126.       n++;
  127.  
  128.   return n;
  129. }
  130.  
  131. // objet (lien) tΘlΘchargΘ ou transfΘrΘ depuis le cache
  132. //
  133. // fermer les paramΦtres de transfert,
  134. // et notamment vΘrifier les fichiers compressΘs (dΘcompresser), callback etc.
  135. int back_finalize(httrackp* opt,cache_back* cache,lien_back* back,int p) {
  136.   if (
  137.       (back[p].status == 0)      // ready
  138.       &&
  139.       (!back[p].testmode)        // not test mode
  140.       &&
  141.       (back[p].r.statuscode>0)   // not internal error
  142.       ) {
  143.     char* state="unknown";
  144.    
  145.     /* dΘcompression */
  146. #if HTS_USEZLIB
  147.     if (gz_is_available && back[p].r.compressed) {
  148.       if (back[p].r.size > 0) {
  149.         //if ( (back[p].r.adr) && (back[p].r.size>0) ) {
  150.         // stats
  151.         back[p].compressed_size=back[p].r.size;
  152.         // en mΘmoire -> passage sur disque
  153.         if (!back[p].r.is_write) {
  154.           back[p].tmpfile[0]='\0';
  155.           strcpybuff(back[p].tmpfile,tempnam(NULL,"httrz"));
  156.           if (back[p].tmpfile[0]) {
  157.             back[p].r.out=fopen(back[p].tmpfile,"wb");
  158.             if (back[p].r.out) {
  159.               if ((back[p].r.adr) && (back[p].r.size>0)) {
  160.                 if ((INTsys)fwrite(back[p].r.adr,1,(INTsys)back[p].r.size,back[p].r.out) != back[p].r.size) {
  161.                   back[p].r.statuscode=-1;
  162.                   strcpybuff(back[p].r.msg,"Write error when decompressing");
  163.                 }
  164.               } else {
  165.                 back[p].tmpfile[0]='\0';
  166.                 back[p].r.statuscode=-1;
  167.                 strcpybuff(back[p].r.msg,"Empty compressed file");
  168.               }
  169.             } else {
  170.               back[p].tmpfile[0]='\0';
  171.               back[p].r.statuscode=-1;
  172.               strcpybuff(back[p].r.msg,"Open error when decompressing");
  173.             }
  174.           }
  175.         }
  176.         // fermer fichier sortie
  177.         if (back[p].r.out!=NULL) {
  178.           fclose(back[p].r.out);
  179.           back[p].r.out=NULL;
  180.         }
  181.         // dΘcompression
  182.         if (back[p].tmpfile[0] && back[p].url_sav[0]) {
  183.           LLint size;
  184.           filecreateempty(back[p].url_sav);      // filenote & co
  185.           if ((size = hts_zunpack(back[p].tmpfile,back[p].url_sav))>=0) {
  186.             back[p].r.size=back[p].r.totalsize=size;
  187.             // fichier -> mΘmoire
  188.             if (!back[p].r.is_write) {
  189.               back[p].r.adr=readfile(back[p].url_sav);
  190.               if (!back[p].r.adr) {
  191.                 back[p].r.statuscode=-1;
  192.                 strcpybuff(back[p].r.msg,"Read error when decompressing");
  193.               }
  194.               remove(back[p].url_sav);
  195.             }
  196.           }
  197.           remove(back[p].tmpfile);
  198.         }
  199.         // stats
  200.         HTS_STAT.total_packed+=back[p].compressed_size;
  201.         HTS_STAT.total_unpacked+=back[p].r.size;
  202.         HTS_STAT.total_packedfiles++;
  203.         // unflag
  204.       }
  205.     }
  206.     back[p].r.compressed=0;
  207. #endif
  208.     
  209.     /* Stats */
  210.     if (cache->txt) {
  211.       char flags[32];
  212.       char s[256];
  213.       time_t tt;
  214.       struct tm* A;
  215.       tt=time(NULL);
  216.       A=localtime(&tt);
  217.       strftime(s,250,"%H:%M:%S",A);
  218.       
  219.       flags[0]='\0';
  220.       /* input flags */
  221.       if (back[p].is_update)
  222.         strcatbuff(flags, "U");   // update request
  223.       else
  224.         strcatbuff(flags, "-");
  225.       if (back[p].range_req_size)
  226.         strcatbuff(flags, "R");   // range request
  227.       else
  228.         strcatbuff(flags, "-");
  229.       /* state flags */
  230.       if (back[p].r.is_file)  // direct to disk
  231.         strcatbuff(flags, "F");
  232.       else
  233.         strcatbuff(flags, "-");
  234.       /* output flags */
  235.       if (!back[p].r.notmodified)
  236.         strcatbuff(flags, "M");   // modified
  237.       else
  238.         strcatbuff(flags, "-");
  239.       if (back[p].r.is_chunk)  // chunked
  240.         strcatbuff(flags, "C");
  241.       else
  242.         strcatbuff(flags, "-");
  243.       if (back[p].r.compressed)
  244.         strcatbuff(flags, "Z");   // gzip
  245.       else
  246.         strcatbuff(flags, "-");
  247.       /* Err I had to split these.. */
  248.       fprintf(cache->txt,"%s\t", s);
  249.       fprintf(cache->txt,LLintP"/", (LLint)back[p].r.size);
  250.       fprintf(cache->txt,LLintP,(LLint)back[p].r.totalsize);
  251.       fprintf(cache->txt,"\t%s\t",flags);
  252.     }
  253.     if (back[p].r.statuscode==200) {
  254.       if (back[p].r.size>=0) {
  255.         if (strcmp(back[p].url_fil,"/robots.txt") !=0 ) {
  256.           HTS_STAT.stat_bytes+=back[p].r.size;
  257.           HTS_STAT.stat_files++;
  258.         }
  259.         if ( (!back[p].r.notmodified) && (opt->is_update) ) { 
  260.           HTS_STAT.stat_updated_files++;       // page modifiΘe
  261.           if (opt->log!=NULL) {
  262.             fspc(opt->log,"info");
  263.             if (back[p].is_update) {
  264.               fprintf(opt->log,"engine: transfer-status: link updated: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  265.             } else {
  266.               fprintf(opt->log,"engine: transfer-status: link added: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  267.             }
  268.             test_flush;
  269.           }
  270.           if (cache->txt) {
  271.             if (back[p].is_update) {
  272.               state="updated";
  273.             } else {
  274.               state="added";
  275.             }
  276.           }
  277.         } else {
  278.           if ( (opt->debug>0) && (opt->log!=NULL) ) {
  279.             fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link recorded: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  280.             test_flush;
  281.           }
  282.           if (cache->txt) {
  283.             if (opt->is_update)
  284.               state="untouched";
  285.             else
  286.               state="added";
  287.           }
  288.         }
  289.       } else {
  290.         if ( (opt->debug>0) && (opt->log!=NULL) ) {
  291.           fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: empty file? (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  292.           test_flush;
  293.         }
  294.         if (cache->txt) {
  295.           state="empty";
  296.         }
  297.       }
  298.     } else {
  299.       if ( (opt->debug>0) && (opt->log!=NULL) ) {
  300.         fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link error (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  301.       }
  302.       if (cache->txt) {
  303.         state="error";
  304.       }
  305.     }
  306.     if (cache->txt) {
  307.       fprintf(cache->txt,
  308.         "%d\t"
  309.         "%s ('%s')\t"
  310.         "%s\t"
  311.         "%s%s\t"
  312.         "%s%s\t%s\t"
  313.         "(from %s%s)"
  314.         LF,
  315.         back[p].r.statuscode,
  316.         state, escape_check_url_addr(back[p].r.msg),
  317.         escape_check_url_addr(back[p].r.contenttype),
  318.         ((back[p].r.etag[0])?"etag:":((back[p].r.lastmodified[0])?"date:":"")), escape_check_url_addr((back[p].r.etag[0])?back[p].r.etag:(back[p].r.lastmodified)),
  319.         escape_check_url_addr(back[p].url_adr),escape_check_url_addr(back[p].url_fil),escape_check_url_addr(back[p].url_sav),
  320.         escape_check_url_addr(back[p].referer_adr),escape_check_url_addr(back[p].referer_fil)
  321.         );
  322.       if (opt->flush)
  323.         fflush(cache->txt);
  324.     }
  325.     
  326.     /* Cache */
  327.     cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  328.     
  329.     // status finished callback
  330. #if HTS_ANALYSTE
  331.     hts_htmlcheck_xfrstatus(&back[p]);
  332. #endif
  333.     return 0;
  334.   }
  335.   return -1;
  336. }
  337.  
  338.  
  339. // effacer entrΘe
  340. int back_delete(lien_back* back,int p) {
  341.   if (p>=0) {    // on sait jamais..
  342.     // VΘrificateur d'intΘgritΘ
  343.     #if DEBUG_CHECKINT
  344.     _CHECKINT(&back[p],"Appel back_delete")
  345.     #endif
  346. #if HTS_DEBUG_CLOSESOCK
  347.     char info[256];
  348.     sprintf(info,"back_delete: #%d\n",p);
  349.     DEBUG_W2(info);
  350. #endif
  351.  
  352.     // LibΘrer tous les sockets, handles, buffers..
  353.     if (back[p].r.soc!=INVALID_SOCKET) {
  354. #if HTS_DEBUG_CLOSESOCK
  355.       DEBUG_W("back_delete: deletehttp\n");
  356. #endif
  357.       deletehttp(&back[p].r);
  358.       back[p].r.soc=INVALID_SOCKET;
  359.     }
  360.     
  361. #if HTS_USEOPENSSL
  362.     /* Free OpenSSL structures */
  363.     if (SSL_is_available && back[p].r.ssl_con) {
  364.       SSL_shutdown(back[p].r.ssl_con);
  365.       SSL_free(back[p].r.ssl_con);
  366.       back[p].r.ssl_con=NULL;
  367.     }
  368.     /*
  369.     if (back[p].r.ssl_soc) {
  370.       BIO_free_all(back[p].r.ssl_soc);
  371.       back[p].r.ssl_soc=NULL;
  372.     }
  373.     */
  374. #endif
  375.     
  376.     if (back[p].r.adr!=NULL) {  // reste un bloc α dΘsallouer
  377.       freet(back[p].r.adr);
  378.       back[p].r.adr=NULL;
  379.     }
  380.     if (back[p].chunk_adr!=NULL) {  // reste un bloc α dΘsallouer
  381.       freet(back[p].chunk_adr);
  382.       back[p].chunk_adr=NULL;
  383.       back[p].chunk_size=0;
  384.       back[p].is_chunk=0;
  385.     }
  386.     // if (back[p].r.is_file) {  // fermer fichier entrΘe
  387.     if (back[p].r.fp!=NULL) {
  388.       fclose(back[p].r.fp);
  389.       back[p].r.fp=NULL;
  390.     }
  391.     // }
  392.  
  393.     /* fichier de sortie */
  394.     if (back[p].r.out!=NULL) {  // fermer fichier sortie
  395.       fclose(back[p].r.out);
  396.       back[p].r.out=NULL;
  397.     }
  398.  
  399.     if (back[p].r.is_write) {     // ecriture directe
  400.       /* Θcrire date "remote" */
  401.       if (strnotempty(back[p].url_sav))          // normalement existe si on a un fichier de sortie
  402.       if (strnotempty(back[p].r.lastmodified))   // last-modified existe
  403.       if (fexist(back[p].url_sav))          // ainsi que le fichier
  404.         set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
  405.  
  406.       /* executer commande utilisateur aprΦs chargement du fichier */
  407.       usercommand(0,NULL,back[p].url_sav);
  408.       back[p].r.is_write=0;
  409.     }
  410.     
  411.     // Tout nettoyer
  412.     memset(&back[p], 0, sizeof(lien_back));  
  413.     back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  414.     
  415.     // Le plus important: libΘrer le champ
  416.     back[p].status=-1;
  417.   }
  418.   return 0;
  419. }
  420.  
  421. /* Space left on backing stack */
  422. int back_stack_available(lien_back* back,int back_max) {
  423.   int p=0,n=0;
  424.   for( ; p < back_max ; p++ )
  425.     if ( back[p].status == -1 )
  426.       n++;
  427.   return n;
  428. }
  429.  
  430. // ajouter un lien en backing
  431. int back_add(lien_back* back,int back_max,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test,int* pass2_ptr) {
  432.   int p=0;
  433.  
  434.   // vΘrifier cohΘrence de adr et fil (non vide!)
  435.   if (strnotempty(adr)==0) {
  436.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  437.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: adr is empty for back_add"LF);
  438.     }
  439.     return -1;    // erreur!
  440.   }
  441.   if (strnotempty(fil)==0) {
  442.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  443.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: fil is empty for back_add"LF);
  444.     }
  445.     return -1;    // erreur!
  446.   }
  447.   // FIN vΘrifier cohΘrence de adr et fil (non vide!)
  448.  
  449.   // rechercher emplacement
  450.   while((p<back_max) && back[p].status!=-1) p++;
  451.   if (back[p].status==-1) {    // ok on a de la place
  452.     back[p].send_too[0]='\0';  // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
  453.  
  454.     // ne sert α rien normalement
  455.     if (back[p].r.soc!=INVALID_SOCKET) {
  456. #if HTS_DEBUG_CLOSESOCK
  457.       DEBUG_W("back_add: deletehttp\n");
  458. #endif
  459.       deletehttp(&back[p].r);
  460.     }
  461.  
  462.     // effacer r
  463.     memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  464.  
  465.     // crΘer entrΘe
  466.     strcpybuff(back[p].url_adr,adr);
  467.     strcpybuff(back[p].url_fil,fil);
  468.     strcpybuff(back[p].url_sav,save);
  469.     back[p].pass2_ptr=pass2_ptr;
  470.     // copier referer si besoin
  471.     strcpybuff(back[p].referer_adr,"");
  472.     strcpybuff(back[p].referer_fil,"");
  473.     if ((referer_adr) && (referer_fil)) {       // existe
  474.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  475.         if (referer_adr[0]!='!') {    // non dΘtruit
  476.           if (strcmp(referer_adr,"file://")) {      // PAS file://
  477.             if (strcmp(referer_adr,"primary")) {      // pas referer 1er lien
  478.               strcpybuff(back[p].referer_adr,referer_adr);
  479.               strcpybuff(back[p].referer_fil,referer_fil);
  480.             }
  481.           }
  482.         }
  483.       }
  484.     }
  485.     // sav ne sert α rien pour le moment
  486.     back[p].r.size=0;                   // rien n'a encore ΘtΘ chargΘ
  487.     back[p].r.soc=INVALID_SOCKET;       // pas de socket
  488.     back[p].r.adr=NULL;                 // pas de bloc de mΘmoire
  489.     back[p].r.is_write=0;               // α priori stockage en mΘmoire
  490.     back[p].maxfile_html=opt->maxfile_html;
  491.     back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
  492.     back[p].testmode=test;              // mode test?
  493.     if (!opt->http10)                 // option "forcer 1.0" dΘsactivΘe
  494.       back[p].http11=1;               // autoriser http/1.1
  495.     back[p].head_request=0;
  496.     if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0)    // HEAD
  497.       back[p].head_request=1;
  498.     else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0)    // test en GET
  499.       back[p].head_request=2;       // test en get
  500.  
  501.     
  502.     /* Stop requested - abort backing */
  503.     if (opt->state.stop) {
  504.       back[p].r.statuscode=-1;        // fatal
  505.       strcpybuff(back[p].r.msg,"mirror stopped by user");
  506.       back[p].status=0;  // terminΘ
  507.       if ((opt->debug>0) && (opt->log!=NULL)) {
  508.         fspc(opt->log,"warning"); fprintf(opt->log,"File not added due to mirror cancel: %s%s"LF,adr,fil); test_flush;
  509.       }            
  510.       return 0;
  511.     }
  512.  
  513.  
  514.     // tester cache
  515.     if ((strcmp(adr,"file://"))           /* pas fichier */
  516.       && ( (!test) || (cache->type==1) )   /* cache prioritaire, laisser passer en test! */
  517.       && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) {  // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
  518.       //if ((!test) && (strcmp(adr,"file://")) 
  519.       //if ((!test) && (strncmp(adr,"ftp://",6)) && (strcmp(adr,"file://")) 
  520. #if HTS_FAST_CACHE
  521.       long int hash_pos;
  522.       int hash_pos_return=0;
  523. #else
  524.       char* a=NULL;
  525. #endif
  526. #if HTS_FAST_CACHE
  527.       if (cache->hashtable) { 
  528. #else
  529.       if (cache->use) { 
  530. #endif
  531.         char buff[HTS_URLMAXSIZE*4];
  532. #if HTS_FAST_CACHE
  533.         strcpybuff(buff,adr); strcatbuff(buff,fil);
  534.         hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  535. #else
  536.         buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  537.         a=strstr(cache->use,buff);
  538. #endif
  539.         
  540.         // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
  541. #if HTS_FAST_CACHE
  542.         if (hash_pos_return) {
  543. #else
  544.         if (a) {
  545. #endif
  546.           if (!test) {      // non mode test
  547. #if HTS_FAST_CACHE
  548.             int pos=hash_pos;
  549. #else
  550.             int pos=-1;
  551.             a+=strlen(buff);
  552.             sscanf(a,"%d",&pos);    // lire position
  553. #endif
  554.             if (pos<0) {    // pas de mise en cache data, vΘrifier existence
  555.               if (fsize(antislash(save)) <= 0) {  // fichier existe pas ou est vide!
  556. #if HTS_FAST_CACHE
  557.                 hash_pos_return=0;
  558. #else
  559.                 a=NULL;    
  560. #endif
  561.                 // dΘvalider car non prΘsent sur disque dans structure originale!!!
  562.                 // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
  563.                 // en Ωtre s√r
  564.                 if (opt->norecatch) {              // tester norecatch
  565.                   if (!fexist(antislash(save))) {  // fichier existe pas mais dΘclarΘ: on l'a effacΘ
  566.                     FILE* fp=fopen(antislash(save),"wb");
  567.                     if (fp) fclose(fp);
  568.                     if (opt->log!=NULL) {
  569.                       fspc(opt->log,"warning"); fprintf(opt->log,"File must have been erased by user, ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  570.                     }
  571.                   }
  572.                 }
  573.               }
  574.             }
  575.           }
  576.         }
  577.         //
  578.       } else
  579. #if HTS_FAST_CACHE
  580.         hash_pos_return=0;
  581. #else
  582.         a=NULL;
  583. #endif
  584.  
  585.       // Existe pas en cache, ou bien pas de cache prΘsent
  586. #if HTS_FAST_CACHE
  587.       if (hash_pos_return) {  // OK existe en cache (et donnΘes aussi)!
  588. #else
  589.       if (a!=NULL) {  // OK existe en cache (et donnΘes aussi)!
  590. #endif
  591.         if (cache->type==1) {   // cache prioritaire (pas de test if-modified..)
  592.                                // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302... 
  593.           // lire dans le cache
  594.           if (!test)
  595.             back[p].r=cache_read(opt,cache,adr,fil,save);
  596.           else
  597.             back[p].r=cache_read(opt,cache,adr,fil,NULL);       // charger en tΩte uniquement du cache
  598.           if (!back[p].r.location) 
  599.             back[p].r.location=back[p].location_buffer;
  600.           else {    /* recopier */
  601.             strcpybuff(back[p].location_buffer,back[p].r.location);
  602.             back[p].r.location=back[p].location_buffer;
  603.           }
  604.  
  605.           /* Interdiction taille par le wizard? --> dΘtruire */
  606.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  607.             if (!back_checksize(opt,&back[p],0)) {
  608.               back[p].status=0;  // FINI
  609.               back[p].r.statuscode=-1;
  610.               if (!back[p].testmode)
  611.                 strcpybuff(back[p].r.msg,"Cached file skipped (too big)");
  612.               else
  613.                 strcpybuff(back[p].r.msg,"Test: Cached file skipped  (too big)");
  614.               return 0;
  615.             }
  616.           }
  617.  
  618.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  619.             if ((opt->debug>0) && (opt->log!=NULL)) {
  620.               if (!test) {
  621.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  622.               } else {
  623.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  624.               }
  625.             }
  626.             back[p].r.notmodified=1;    // fichier non modifiΘ
  627.             back[p].status=0;  // OK prΩt
  628.  
  629.             // finalize transfer
  630.             if (!test) {
  631.               if (back[p].r.statuscode>0) {
  632.                 back_finalize(opt,cache,back,p);
  633.               }
  634.             }
  635.  
  636.             return 0;
  637.           } else {  // erreur
  638.             // effacer r
  639.             memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  640.             // et continuer (chercher le fichier)
  641.           }
  642.           
  643.         } else if (cache->type==2) {    // si en cache, demander de tester If-Modified-Since
  644.           htsblk* r=cache_header(opt,cache,adr,fil);
  645.  
  646.           /* Interdiction taille par le wizard? */
  647.           {
  648.             LLint save_totalsize=back[p].r.totalsize;
  649.             back[p].r.totalsize=r->totalsize;
  650.             if (!back_checksize(opt,&back[p],1)) {
  651.               r=NULL;
  652.               //
  653.               back[p].status=0;  // FINI
  654.               deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
  655.               if (!back[p].testmode)
  656.                 strcpybuff(back[p].r.msg,"File too big");
  657.               else
  658.                 strcpybuff(back[p].r.msg,"Test: File too big");
  659.               return 0;
  660.             }
  661.             back[p].r.totalsize=save_totalsize;
  662.           }
  663.           
  664.           if (r) {
  665.             if (r->statuscode==200) {     // uniquement des 200 (OK)
  666.               if (strnotempty(r->etag)) {  // ETag (RFC2616)
  667.                 /*
  668.                 - If both an entity tag and a Last-Modified value have been
  669.                 provided by the origin server, SHOULD use both validators in
  670.                 cache-conditional requests. This allows both HTTP/1.0 and
  671.                 HTTP/1.1 caches to respond appropriately.
  672.                 */
  673.                 if (strnotempty(r->lastmodified))
  674.                   sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r->etag,r->lastmodified);
  675.                 else
  676.                   sprintf(back[p].send_too,"If-None-Match: %s\r\n",r->etag);
  677.               }
  678.               else if (strnotempty(r->lastmodified))
  679.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r->lastmodified);
  680.               else if (strnotempty(cache->lastmodified))
  681.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  682.               
  683.               /* this is an update of a file */
  684.               if (strnotempty(back[p].send_too))
  685.                 back[p].is_update=1;
  686.               back[p].r.req.nocompression=1;   /* Do not compress when updating! */
  687.               
  688.             }
  689.             /* else if (strnotempty(cache->lastmodified))
  690.             sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  691.             */
  692.           }
  693. #if DEBUGCA
  694.           printf("..is modified test %s\n",back[p].send_too);
  695. #endif
  696.         } 
  697.         // Okay, pas trouvΘ dans le cache
  698.         // Et si le fichier existe sur disque?
  699.         // Pas dans le cache: fichier n'a pas ΘtΘ transfΘrΘ du tout, donc pas sur disque?
  700.       } else {
  701.         if (fexist(save)) {    // fichier existe? aghl!
  702.           LLint sz=fsize(save);
  703.           // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
  704.           // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
  705.           // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
  706.           // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
  707.           if ((ishtml(save) != 1) && (ishtml(back[p].url_fil)!=1)) {   // NON HTML (liens changΘs!!)
  708.             if (sz>0) {    // Fichier non vide? (question bΩte, sinon on transfert tout!)
  709.               if (strnotempty(cache->lastmodified)) {     /* pas de If-.. possible */
  710.                 /*if ( (!opt->http10) && (strnotempty(cache->lastmodified)) ) { */    /* ne pas forcer 1.0 */
  711. #if DEBUGCA
  712.                 printf("..if unmodified since %s size "LLintP"\n",cache->lastmodified,(LLint)sz);
  713. #endif
  714.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  715.                   fspc(opt->log,"debug"); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  716.                 }
  717.                 
  718.                 /* impossible - don't have etag or date
  719.                 if (strnotempty(back[p].r.etag)) {  // ETag (RFC2616)
  720.                 sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
  721.                 back[p].http11=1;    // En tΩte 1.1
  722.                 } else if (strnotempty(back[p].r.lastmodified)) {
  723.                 sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
  724.                 back[p].http11=1;    // En tΩte 1.1
  725.                 } else 
  726.                 */
  727.                 if (strlen(cache->lastmodified)) {
  728.                   sprintf(back[p].send_too,
  729.                     "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
  730.                     ,cache->lastmodified,(LLint)sz);
  731.                   back[p].http11=1;    // En tΩte 1.1
  732.                   back[p].range_req_size=sz;
  733.                   back[p].r.req.range_used=1;
  734.                   back[p].r.req.nocompression=1;
  735.                 } else {
  736.                   if ((opt->debug>0) && (opt->log!=NULL)) {
  737.                     fspc(opt->log,"warning"); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  738.                   }
  739.                 }
  740.                 
  741.               } else { 
  742.                 if ((opt->debug>0) && (opt->errlog!=NULL)) {
  743.                   fspc(opt->errlog,"warning");
  744.                   /*
  745.                   if (opt->http10)
  746.                   fprintf(opt->errlog,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
  747.                   else
  748.                   */
  749.                   fprintf(opt->errlog,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  750.                   test_flush;
  751.                 }
  752.                 /* Sinon requΩte normale... */
  753.                 back[p].http11=0;
  754.               }
  755.             } else if (opt->norecatch) {              // tester norecatch
  756.               filenote(save,NULL);       // ne pas purger tout de mΩme
  757.               back[p].status=0;  // OK prΩt
  758.               back[p].r.statuscode=-1;  // erreur
  759.               strcpybuff(back[p].r.msg,"Null-size file not recaught");
  760.               return 0;
  761.             }
  762.           } else {
  763.             if ((opt->debug>0) && (opt->errlog!=NULL)) {
  764.               fspc(opt->errlog,"warning");
  765.               fprintf(opt->errlog,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  766.               test_flush;
  767.             }
  768.             /* Sinon requΩte normale... */
  769.             back[p].http11=0;
  770.           }
  771.         }
  772.       }
  773.     }
  774.  
  775.  
  776.     {
  777.       ///htsblk r;   non directement dans la structure-rΘponse!
  778.       T_SOC soc;
  779.       
  780.       // ouvrir liaison, envoyer requΦte
  781.       // ne pas traiter ou recevoir l'en tΩte immΘdiatement
  782.       memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  783.       // recopier proxy
  784.       memcpy(&(back[p].r.req.proxy), &opt->proxy, sizeof(opt->proxy));
  785.       // et user-agent
  786.       strcpybuff(back[p].r.req.user_agent,opt->user_agent);
  787.       strcpybuff(back[p].r.req.lang_iso,opt->lang_iso);
  788.       back[p].r.req.user_agent_send=opt->user_agent_send;
  789.       // et http11
  790.       back[p].r.req.http11=back[p].http11;
  791.       back[p].r.req.nocompression=opt->nocompression;
  792.  
  793.       // mode ftp, court-circuit!
  794.       if (strfield(back[p].url_adr,"ftp://")) {
  795.         if (back[p].testmode) {
  796.           if ((opt->debug>1) && (opt->errlog!=NULL)) {
  797.             fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: forbidden test with ftp link for back_add"LF);
  798.           }
  799.           return -1;    // erreur pas de test permis
  800.         }
  801.         if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
  802.           back[p].status=1000;   // connexion ftp
  803. #if USE_BEGINTHREAD
  804.           launch_ftp(&(back[p]));
  805. #else
  806.           {
  807.             char nid[32];
  808.             sprintf(nid,"htsftp%d-in_progress.lock",p);
  809.             strcpybuff(back[p].location_buffer,fconcat(opt->path_log,nid));
  810.           }
  811.           launch_ftp(&(back[p]),back[p].location_buffer,opt->exec);
  812. #endif
  813.           return 0;
  814.         }
  815.       }
  816. #if HTS_USEOPENSSL
  817.       else if (SSL_is_available && strfield(back[p].url_adr,"https://")) {        // let's rock
  818.         back[p].r.ssl = 1;
  819.         // back[p].r.ssl_soc = NULL;
  820.         back[p].r.ssl_con = NULL;
  821.       }
  822. #endif
  823.       
  824. #if HTS_XGETHOST
  825. #if HDEBUG
  826.       printf("back_solve..\n");
  827. #endif
  828.       back[p].status=101;    // tentative de rΘsolution du nom de host
  829.       soc=INVALID_SOCKET;    // pas encore ouverte
  830.       back_solve(&back[p]);  // prΘparer
  831.       if (host_wait(&back[p])) {  // prΩt, par ex fichier ou dispo dans dns
  832. #if HDEBUG
  833.       printf("ok, dns cache ready..\n");
  834. #endif
  835.         soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  836.         if (soc==INVALID_SOCKET) {
  837.           back[p].status=0;  // fini, erreur
  838.         }
  839.       }
  840. //
  841. #else
  842. //
  843. #if CNXDEBUG
  844.       printf("XFopen..\n");
  845. #endif
  846.  
  847.       if (strnotempty(back[p].send_too))    // envoyer un if-modified-since
  848. #if HTS_XCONN
  849.       soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  850. #else
  851.       soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
  852. #endif
  853.       else
  854. #if HTS_XCONN
  855.         soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
  856. #else
  857.       soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
  858. #endif
  859. #endif
  860.       if (opt->timeout>0) {    // gestion du opt->timeout
  861.         back[p].timeout=opt->timeout;
  862.         back[p].timeout_refresh=time_local();
  863.       } else {
  864.         back[p].timeout=-1;    // pas de gestion (default)
  865.       }
  866.       
  867.       if (opt->rateout>0) {    // gestion d'un taux minimum de transfert tolΘrΘ
  868.         back[p].rateout=opt->rateout;
  869.         back[p].rateout_time=time_local();
  870.       } else {
  871.         back[p].rateout=-1;    // pas de gestion (default)
  872.       }
  873.  
  874.       // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
  875.       // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
  876.       //if ((back[p].statuscode!=200) || (soc<0)) { // ERREUR HTTP/autre
  877.  
  878. #if CNXDEBUG
  879. printf("Xfopen ok, poll..\n");
  880. #endif
  881.  
  882. #if HTS_XGETHOST
  883.     if (soc!=INVALID_SOCKET)
  884.       if (back[p].status==101) {  // pas d'erreur
  885.         if (!back[p].r.is_file)
  886.           back[p].status=100;   // connexion en cours
  887.         else
  888.           back[p].status=1;     // fichier
  889.       }
  890.  
  891. #else
  892.       if (soc==INVALID_SOCKET) { // erreur socket
  893.         back[p].status=0;    // FINI
  894.         //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
  895.         back[p].r.soc=INVALID_SOCKET;
  896.       } else {
  897.         if (!back[p].r.is_file)
  898. #if HTS_XCONN
  899.           back[p].status=100;   // connexion en cours
  900. #else
  901.           back[p].status=99;    // chargement en tΩte en cours
  902. #endif
  903.         else
  904.           back[p].status=1;     // chargement fichier
  905. #if BDEBUG==1
  906.         printf("..loading header\n");
  907. #endif
  908.       }
  909. #endif
  910.       
  911.     }
  912.  
  913.  
  914.     // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
  915.     // le lien est considΘrΘ comme traitΘ
  916.     //if (back[p].soc<0)  // erreur
  917.     //  return -1;
  918.  
  919.     return 0;
  920.   } else {
  921.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  922.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: no space left in stack for back_add"LF);
  923.     }
  924.     return -1;    // plus de place
  925.   }
  926. }
  927.  
  928.  
  929.  
  930. #if HTS_XGETHOST
  931. #if USE_BEGINTHREAD
  932. // lancement multithread du robot
  933. PTHREAD_TYPE Hostlookup(void* iadr_p) {
  934.   char iadr[256];
  935.   t_dnscache* cache=_hts_cache();  // adresse du cache
  936.   t_hostent* hp;
  937.   int error_found=0;
  938.  
  939.   // recopier (aprΦs id:pass)
  940. #if DEBUGDNS 
  941.   printf("resolv in background: %s\n",jump_identification(iadr_p));
  942. #endif
  943.   strcpybuff(iadr,jump_identification(iadr_p));
  944.   // couper Θventuel :
  945.   {
  946.     char *a;
  947.     if ( (a=jump_toport(iadr)) )
  948.       *a='\0';          // get rid of it
  949.   }
  950.   freet(iadr_p);
  951.  
  952.   // attendre que le cache dns soit prΩt
  953.   while(_hts_lockdns(-1));  // attendre libΘration
  954.   _hts_lockdns(1);          // locker
  955.   while(cache->n) {
  956.     if (strcmp(cache->iadr,iadr)==0) {
  957.       error_found=1;
  958.     }
  959.     cache=cache->n;    // calculer queue
  960.   }
  961.   if (strcmp(cache->iadr,iadr)==0) {
  962.     error_found=1;
  963.   }
  964.  
  965.   if (!error_found) {
  966.     // en gros copie de hts_gethostbyname sans le return
  967.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  968.     if (cache->n!=NULL) {
  969.       t_fullhostent fullhostent_buffer;
  970.       strcpybuff(cache->n->iadr,iadr);
  971.       cache->n->host_length=0;        /* pour le moment rien */
  972.       cache->n->n=NULL;
  973.       _hts_lockdns(0);          // dΘlocker
  974.       
  975.       /* resolve */
  976. #if DEBUGDNS 
  977.       printf("gethostbyname() in progress for %s\n",iadr);
  978. #endif
  979.       cache->n->host_length=-1;
  980.       memset(cache->n->host_addr, 0, sizeof(cache->n->host_addr));
  981.       hp=vxgethostbyname(iadr, &fullhostent_buffer);
  982.       if (hp!=NULL) {
  983.         memcpy(cache->n->host_addr, hp->h_addr, hp->h_length);
  984.         cache->n->host_length = hp->h_length;
  985.       }
  986.     } else 
  987.     _hts_lockdns(0);          // dΘlocker
  988.   } else {
  989. #if DEBUGDNS 
  990.     printf("aborting resolv for %s (found)\n",iadr);
  991. #endif
  992.     _hts_lockdns(0);          // dΘlocker
  993.   }
  994.   // fin de copie de hts_gethostbyname
  995.  
  996. #if DEBUGDNS 
  997.   printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
  998. #endif
  999.  
  1000.   return PTHREAD_RETURN;     /* _endthread implied  */
  1001. }
  1002. #endif
  1003.  
  1004. // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
  1005. // si c'est un fichier, la rΘsolution est immΘdiate
  1006. // idem pour ftp://
  1007. void back_solve(lien_back* back) {
  1008.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1009.   //## if (back->url_adr[0]!=lOCAL_CHAR) {  // qq chose α prΘparer
  1010.     char* a;
  1011.     if (!(back->r.req.proxy.active))
  1012.       a=back->url_adr;
  1013.     else
  1014.       a=back->r.req.proxy.name;
  1015.     a = jump_protocol(a);
  1016.     if (!hts_dnstest(a)) {   // non encore testΘ!..
  1017.       // inscire en thread
  1018. #if HTS_WIN
  1019.       // Windows
  1020. #if USE_BEGINTHREAD
  1021.       {
  1022.         char* p = calloct(strlen(a)+2,1);
  1023.         if (p) {
  1024.           strcpybuff(p,a);
  1025.           _beginthread( Hostlookup , 0, p );
  1026.         }
  1027.       }
  1028. #else
  1029.       /*t_hostent* h=*/
  1030.       /*hts_gethostbyname(a);*/  // calcul
  1031. #endif
  1032. #else
  1033. #if USE_BEGINTHREAD
  1034.         char* p = calloct(strlen(a)+2,1);
  1035.         if (p) {
  1036.           strcpybuff(p,a);
  1037.           _beginthread( Hostlookup , 0, p );
  1038.         }
  1039. #else
  1040.       // Sous Unix, le gethostbyname() est bloquant..
  1041.       /*t_hostent* h=*/
  1042.       /*hts_gethostbyname(a);*/  // calcul
  1043. #endif
  1044. #endif
  1045.     }
  1046.   }
  1047. }
  1048.  
  1049. // dΘtermine si le host a pu Ωtre rΘsolu
  1050. int host_wait(lien_back* back) {
  1051.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1052.   //## if (back->url_adr[0]!=lOCAL_CHAR) {
  1053.     if (!(back->r.req.proxy.active)) {
  1054.       return (hts_dnstest(back->url_adr));
  1055.     } else {
  1056.       return (hts_dnstest(back->r.req.proxy.name));      
  1057.     }
  1058.   } else return 1;    // prΩt, fichier local
  1059. }
  1060. #endif
  1061.  
  1062.  
  1063. // Θlimine les fichiers non html en backing (anticipation)
  1064. // cleanup non-html files in backing to save backing space
  1065. // and allow faster "save in cache" operation
  1066. void back_clean(httrackp* opt,cache_back* cache,lien_back* back,int back_max) {
  1067.   int i;
  1068.   for(i=0;i<back_max;i++) {
  1069.     if (back[i].status == 0) {                                   // ready
  1070.       if (!back[i].testmode) {                                   // not test mode
  1071.         if (strnotempty(back[i].url_sav)) {                      // filename exists
  1072.           if (back[i].r.is_write) {                              // not in memory (on disk, ready)
  1073.             if (back[i].r.size>0) {                              // size>0
  1074.               if (back[i].r.statuscode==200) {                   // HTTP "OK"
  1075.                 if (!is_hypertext_mime(back[i].r.contenttype)) { // not HTML/hypertext
  1076.                   if (!may_be_hypertext_mime(back[i].r.contenttype)) { // may NOT be parseable mime type
  1077.                     if (back[i].pass2_ptr) {
  1078.                       // finalize
  1079.                       // // back_finalize(opt,cache,back,i);
  1080.                       // stats
  1081.                       //HTS_STAT.stat_bytes+=back[i].r.size;
  1082.                       //HTS_STAT.stat_files++;
  1083.                       //if ( (!back[i].r.notmodified) && (opt->is_update) ) { 
  1084.                       //  HTS_STAT.stat_updated_files++;       // page modifiΘe
  1085.                       //}
  1086.                       //cache_mayadd(opt,cache,&back[i].r,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  1087.                       *back[i].pass2_ptr=-1;  // Done!
  1088.                       back_delete(back,i);    // Delete backing entry
  1089.                       if ((opt->debug>0) && (opt->log!=NULL)) {
  1090.                         fspc(opt->log,"info"); fprintf(opt->log,"File successfully written in background: %s"LF,back[i].url_sav); test_flush;
  1091.                       }
  1092.                     }
  1093.                   }
  1094.                 }
  1095.               }
  1096.             }
  1097.           }
  1098.         }
  1099.       }
  1100.     }
  1101.   }            
  1102. }
  1103.  
  1104.  
  1105. // attente (gestion des buffers des sockets)
  1106. void back_wait(lien_back* back,int back_max,httrackp* opt,cache_back* cache,TStamp stat_timestart) {
  1107.   int i;
  1108.   T_SOC nfds=INVALID_SOCKET;
  1109.   fd_set fds,fds_c,fds_e;     // fds pour lecture, connect (write), et erreur
  1110.   int nsockets;     // nbre sockets
  1111.   LLint max_read_bytes;  // max bytes read per sockets
  1112.   struct timeval tv;
  1113.   int do_wait=0;
  1114.   int gestion_timeout=0;
  1115.   int busy_recv=0;     // pas de donnΘes pour le moment   
  1116.   int busy_state=0;    // pas de connexions
  1117.   int max_loop;  // nombre de boucles max α parcourir..
  1118. #if HTS_ANALYSTE
  1119.   int max_loop_chk=0;
  1120. #endif
  1121.  
  1122.  
  1123.   // max. number of loops
  1124.   max_loop=8;
  1125.  
  1126. #if 1
  1127.   // Cleanup the stack to save space!
  1128.   back_clean(opt,cache,back,back_max);
  1129. #endif
  1130.  
  1131.   // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
  1132.   do_wait=0;
  1133.   gestion_timeout=0;
  1134.   do {
  1135.     int max_c;
  1136.     busy_state=busy_recv=0;
  1137.  
  1138. #if 0
  1139.     check_rate(stat_timestart,opt->maxrate);    // vΘrifier taux de transfert
  1140. #endif
  1141.     // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
  1142.     FD_ZERO(&fds);
  1143.     FD_ZERO(&fds_c);
  1144.     FD_ZERO(&fds_e);
  1145.     nsockets=0;
  1146.     max_read_bytes=TAILLE_BUFFER;     // maximum bytes that can be read
  1147.     nfds=INVALID_SOCKET;
  1148.  
  1149.     max_c=1;
  1150.     for(i=0;i<back_max;i++) {
  1151.  
  1152.       // en cas de gestion du connect prΘemptif
  1153. #if HTS_XCONN
  1154.       if (back[i].status==100) {      // connexion
  1155.         do_wait=1;
  1156.  
  1157.         // noter socket write
  1158.         FD_SET(back[i].r.soc,&fds_c);
  1159.         
  1160.         // noter socket erreur
  1161.         FD_SET(back[i].r.soc,&fds_e);
  1162.  
  1163.         // calculer max
  1164.         if (max_c) {
  1165.           max_c=0;
  1166.           nfds=back[i].r.soc;
  1167.         } else if (back[i].r.soc>nfds) {
  1168.           // ID socket la plus ΘlevΘe
  1169.           nfds=back[i].r.soc;
  1170.         }
  1171.         
  1172.       } else
  1173. #endif
  1174. #if HTS_XGETHOST
  1175.       if (back[i].status==101) {      // attente
  1176.         // rien α faire..
  1177.       } else
  1178. #endif
  1179.       // poll pour la lecture sur les sockets
  1180.       if ((back[i].status>0) && (back[i].status<100)) {  // en rΘception http
  1181.             
  1182. #if BDEBUG==1
  1183.         //printf("....socket in progress: %d\n",back[i].r.soc);
  1184. #endif
  1185.         // non local et non ftp
  1186.         if (!back[i].r.is_file) {
  1187.         //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
  1188.           
  1189.           // vΘrification de sΘcuritΘ
  1190.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1191.             do_wait=1;
  1192.             
  1193.             // noter socket read
  1194.             FD_SET(back[i].r.soc,&fds);
  1195.             
  1196.             // noter socket error
  1197.             FD_SET(back[i].r.soc,&fds_e);
  1198.             
  1199.             // incrΘmenter nombre de sockets
  1200.             nsockets++;
  1201.  
  1202.             // calculer max
  1203.             if (max_c) {
  1204.               max_c=0;
  1205.               nfds=back[i].r.soc;
  1206.             } else if (back[i].r.soc>nfds) {
  1207.               // ID socket la plus ΘlevΘe
  1208.               nfds=back[i].r.soc;
  1209.             }
  1210.           } else {
  1211.             back[i].r.statuscode=-4;
  1212.             if (back[i].status==100)
  1213.               strcpybuff(back[i].r.msg,"Connect Error");
  1214.             else
  1215.               strcpybuff(back[i].r.msg,"Receive Error");
  1216.             back[i].status=0;  // terminΘ
  1217.             if ((opt->debug>0) && (opt->log!=NULL)) {
  1218.               fspc(opt->log,"warning"); fprintf(opt->log,"Unexpected socket error during pre-loop"LF); test_flush;
  1219.             }            
  1220.           }
  1221. #if WIDE_DEBUG
  1222.           else {
  1223.             DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
  1224.           }
  1225. #endif
  1226.           
  1227.         }
  1228.         
  1229.       }
  1230.     }    
  1231.     nfds++;
  1232.     
  1233.     if (do_wait) {  // attendre
  1234.       // temps d'attente max: 2.5 seconde
  1235.       tv.tv_sec=HTS_SOCK_SEC;
  1236.       tv.tv_usec=HTS_SOCK_MS;
  1237.       
  1238. #if BDEBUG==1
  1239.       printf("..select\n");
  1240. #endif
  1241.       
  1242.       // poller les sockets-attention au noyau sous Unix..
  1243. #if HTS_WIDE_DEBUG    
  1244.       DEBUG_W("select\n");
  1245. #endif
  1246.       select(nfds,&fds,&fds_c,&fds_e,&tv);
  1247. #if HTS_WIDE_DEBUG    
  1248.       DEBUG_W("select done\n");
  1249. #endif      
  1250.     }
  1251.     
  1252.     // maximum data which can be received for a socket, if limited
  1253.     if (nsockets) {
  1254.       if (opt->maxrate>0) {
  1255.         max_read_bytes = ( check_downloadable_bytes(opt->maxrate) / nsockets );
  1256.       }
  1257.     }
  1258.     if (!max_read_bytes)
  1259.       busy_recv=0;
  1260.     
  1261.     // recevoir les donnΘes arrivΘes
  1262.     for(i=0;i<back_max;i++) {
  1263.       
  1264.       if (back[i].status>0) {
  1265.         if (!back[i].r.is_file) {  // not file..
  1266.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1267.             int err=FD_ISSET(back[i].r.soc,&fds_e);
  1268.             if (err) {
  1269.               if (back[i].r.soc!=INVALID_SOCKET) {
  1270. #if HTS_DEBUG_CLOSESOCK
  1271.                 DEBUG_W("back_wait: deletehttp\n");
  1272. #endif
  1273.                 deletehttp(&back[i].r);
  1274.               }
  1275.               back[i].r.soc=INVALID_SOCKET;
  1276.               back[i].r.statuscode=-4;
  1277.               if (back[i].status==100)
  1278.                 strcpybuff(back[i].r.msg,"Connect Error");
  1279.               else
  1280.                 strcpybuff(back[i].r.msg,"Receive Error");
  1281.               back[i].status=0;  // terminΘ
  1282.             }
  1283.           }
  1284.         }
  1285.       }
  1286.       
  1287.       // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
  1288.       if (back[i].status==100) {   // attendre connect
  1289.         int dispo=0;
  1290.         // vΘrifier l'existance de timeout-check
  1291.         if (!gestion_timeout)
  1292.           if (back[i].timeout>0)
  1293.             gestion_timeout=1;
  1294.           
  1295.           // connectΘ?
  1296.           dispo=FD_ISSET(back[i].r.soc,&fds_c);
  1297.           if (dispo) {    // ok connected!!
  1298.             busy_state=1;
  1299.             
  1300. #if HTS_USEOPENSSL
  1301.             /* SSL mode */
  1302.             if (SSL_is_available && back[i].r.ssl) {
  1303.               // handshake not yet launched
  1304.               if (!back[i].r.ssl_con) {
  1305.                 SSL_CTX_set_options(openssl_ctx, SSL_OP_ALL);
  1306.                 // new session
  1307.                 back[i].r.ssl_con = SSL_new(openssl_ctx);
  1308.                 if (back[i].r.ssl_con) {
  1309.                   SSL_clear(back[i].r.ssl_con);
  1310.                   if (SSL_set_fd(back[i].r.ssl_con, back[i].r.soc) == 1) {
  1311.                     SSL_set_connect_state(back[i].r.ssl_con);
  1312.                     back[i].status = 102;         /* handshake wait */
  1313.                   } else
  1314.                     back[i].r.statuscode=-6;
  1315.                 } else
  1316.                   back[i].r.statuscode=-6;
  1317.               }
  1318.               /* Error */
  1319.               if (back[i].r.statuscode == -6) {
  1320.                 strcpybuff(back[i].r.msg, "bad SSL/TLS handshake");
  1321.                 deletehttp(&back[i].r);
  1322.                 back[i].r.soc=INVALID_SOCKET;
  1323.                 back[i].r.statuscode=-5;
  1324.                 back[i].status=0;
  1325.               }
  1326.             }
  1327.             
  1328. #endif
  1329.  
  1330. #if BDEBUG==1
  1331.           printf("..connect ok on socket %d\n",back[i].r.soc);
  1332. #endif
  1333.           
  1334.           if ((back[i].r.soc != INVALID_SOCKET) && (back[i].status==100)) {
  1335.             /* limit nb. connections/seconds to avoid server overload */
  1336.             if (opt->maxconn>0) {
  1337.               Sleep(1000/opt->maxconn);
  1338.             }
  1339.             
  1340.             if (back[i].timeout>0) {    // refresh timeout si besoin est
  1341.               back[i].timeout_refresh=time_local();
  1342.             }
  1343.             if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1344.               back[i].rateout_time=time_local();
  1345.             }
  1346.             // envoyer header
  1347.             //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0)    // vrai get
  1348.             if (!back[i].head_request)
  1349.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1350.             else if (back[i].head_request==2)  // test en GET!
  1351.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1352.             else        // test!
  1353.               http_sendhead(opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1354.             back[i].status=99;  // attendre en tΩte maintenant
  1355.           }
  1356.         }
  1357.         
  1358.         // attente gethostbyname
  1359.       }
  1360. #if HTS_USEOPENSSL
  1361.       else if (SSL_is_available && back[i].status==102) {   // wait for SSL handshake
  1362.         /* SSL mode */
  1363.         if (back[i].r.ssl) {
  1364.           int conn_code;
  1365.           if ((conn_code = SSL_connect(back[i].r.ssl_con)) <= 0) {
  1366.             /* non blocking I/O, will retry */
  1367.             int err_code = SSL_get_error(back[i].r.ssl_con, conn_code);
  1368.             if (
  1369.               (err_code != SSL_ERROR_WANT_READ)
  1370.               &&
  1371.               (err_code != SSL_ERROR_WANT_WRITE)
  1372.               ) {
  1373.               char tmp[256];
  1374.               tmp[0]='\0';
  1375.               ERR_error_string(err_code, tmp);
  1376.               back[i].r.msg[0]='\0';
  1377.               strncatbuff(back[i].r.msg, tmp, sizeof(back[i].r.msg) - 2);
  1378.               if (!strnotempty(back[i].r.msg)) {
  1379.                 sprintf(back[i].r.msg, "SSL/TLS error %d", err_code);
  1380.               }
  1381.               deletehttp(&back[i].r);
  1382.               back[i].r.soc=INVALID_SOCKET;
  1383.               back[i].r.statuscode=-5;
  1384.               back[i].status=0;
  1385.             }
  1386.           } else {        /* got it! */
  1387.             back[i].status=100;       // back to waitconnect
  1388.           }
  1389.         } else {
  1390.           strcpybuff(back[i].r.msg, "unexpected SSL/TLS error");
  1391.           deletehttp(&back[i].r);
  1392.           back[i].r.soc=INVALID_SOCKET;
  1393.           back[i].r.statuscode=-5;
  1394.           back[i].status=0;
  1395.         }
  1396.         
  1397.       }
  1398. #endif
  1399. #if HTS_XGETHOST
  1400.       else if (back[i].status==101) {  // attendre gethostbyname
  1401. #if DEBUGDNS 
  1402.         //printf("status 101 for %s\n",back[i].url_adr);
  1403. #endif
  1404.  
  1405.         if (!gestion_timeout)
  1406.           if (back[i].timeout>0)
  1407.             gestion_timeout=1;
  1408.  
  1409.         if (host_wait(&back[i])) {    // prΩt
  1410.           back[i].status=100;        // attente connexion
  1411.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  1412.             back[i].timeout_refresh=time_local();
  1413.           }
  1414.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1415.             back[i].rateout_time=time_local();
  1416.           }
  1417.  
  1418.           back[i].r.soc=http_xfopen(0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
  1419.           if (back[i].r.soc==INVALID_SOCKET) {
  1420.             back[i].status=0;  // fini, erreur
  1421.             if (back[i].r.soc!=INVALID_SOCKET) {
  1422. #if HTS_DEBUG_CLOSESOCK
  1423.               DEBUG_W("back_wait(2): deletehttp\n");
  1424. #endif
  1425.               deletehttp(&back[i].r);
  1426.             }
  1427.             back[i].r.soc=INVALID_SOCKET;
  1428.             back[i].r.statuscode=-5;
  1429.             if (strnotempty(back[i].r.msg)==0) 
  1430.               strcpybuff(back[i].r.msg,"Unable to resolve host name");
  1431.           }
  1432.         }
  1433.         
  1434.  
  1435.       // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
  1436.       }
  1437. #endif
  1438. #if USE_BEGINTHREAD
  1439.       // ..rien α faire, c'est magic les threads
  1440. #else
  1441.       else if (back[i].status==1000) {  // en rΘception ftp
  1442.         if (!fexist(back[i].location_buffer)) {    // terminΘ
  1443.           FILE* fp;
  1444.           fp=fopen(fconcat(back[i].location_buffer,".ok"),"rb");
  1445.           if (fp) {
  1446.             int j=0;
  1447.             fscanf(fp,"%d ",&(back[i].r.statuscode));
  1448.             while(!feof(fp)) {
  1449.               int c = fgetc(fp);
  1450.               if (c!=EOF)
  1451.                 back[i].r.msg[j++]=c;
  1452.             }
  1453.             back[i].r.msg[j++]='\0';
  1454.             fclose(fp);
  1455.             remove(fconcat(back[i].location_buffer,".ok"));
  1456.             strcpybuff(fconcat(back[i].location_buffer,".ok"),"");
  1457.           } else {
  1458.             strcpybuff(back[i].r.msg,"Unknown ftp result, check if file is ok");
  1459.             back[i].r.statuscode=-1;
  1460.           }
  1461.           back[i].status=0;
  1462.           // finalize transfer
  1463.           if (back[i].r.statuscode>0) {
  1464.             back_finalize(opt,cache,back,i);
  1465.           }
  1466.         }
  1467.       }
  1468. #endif
  1469.       else if ((back[i].status>0) && (back[i].status<1000)) {  // en rΘception http
  1470.         int dispo=0;
  1471.         
  1472.         // vΘrifier l'existance de timeout-check
  1473.         if (!gestion_timeout)
  1474.           if (back[i].timeout>0)
  1475.             gestion_timeout=1;
  1476.           
  1477.           // donnΘes dispo?
  1478.           //## if (back[i].url_adr[0]!=lOCAL_CHAR)
  1479.           if (!back[i].r.is_file) {
  1480.             dispo=FD_ISSET(back[i].r.soc,&fds);
  1481.           }
  1482.           else
  1483.             dispo=1;
  1484.  
  1485.           // Check transfer rate!
  1486.           if (!max_read_bytes)
  1487.             dispo=0;                // limit transfer rate
  1488.           
  1489.           if (dispo) {    // donnΘes dispo
  1490.             LLint retour_fread;
  1491.             busy_recv=1;    // on rΘcupΦre encore
  1492. #if BDEBUG==1
  1493.             printf("..data available on socket %d\n",back[i].r.soc);
  1494. #endif
  1495.  
  1496.             
  1497.             // range size hack old location
  1498.  
  1499. #if HTS_DIRECTDISK
  1500.             // Court-circuit:
  1501.             // Peut-on stocker le fichier directement sur disque?
  1502.             // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
  1503.             if (back[i].status) {
  1504.               if (back[i].r.is_write==0) {  // mode mΘmoire
  1505.                 if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1506.                   if (!back[i].testmode) {  // pas mode test
  1507.                     if (strnotempty(back[i].url_sav)) {
  1508.                       if (strcmp(back[i].url_fil,"/robots.txt")) {
  1509.                         if (back[i].r.statuscode==200) {  // 'OK'
  1510.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1511.                             if (opt->getmode&2) {    // on peut ecrire des non html
  1512.                               back[i].r.is_write=1;    // Θcrire
  1513.                               if (back[i].r.compressed
  1514.                                 &&
  1515.                                 /* .gz are *NOT* depacked!! */
  1516.                                 (strfield(get_ext(back[i].url_sav),"gz") == 0)
  1517.                                 ) {
  1518.                                 back[i].tmpfile[0]='\0';
  1519.                                 strcpybuff(back[i].tmpfile,tempnam(NULL,"httrZ"));
  1520.                                 if (back[i].tmpfile[0])
  1521.                                   back[i].r.out=fopen(back[i].tmpfile,"wb");
  1522.                               } else {
  1523.                                 back[i].r.compressed=0;
  1524.                                 back[i].r.out=filecreate(back[i].url_sav);
  1525.                               }
  1526. #if HDEBUG
  1527.                               printf("direct-disk: %s\n",back[i].url_sav);
  1528. #endif
  1529.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1530.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1531.                               }
  1532.                               
  1533.                               if (back[i].r.out==NULL) {
  1534.                                 if (opt->errlog) {
  1535.                                   fspc(opt->errlog,"error");
  1536.                                   fprintf(opt->errlog,"Unable to save file %s"LF,back[i].url_sav);
  1537.                                   test_flush;
  1538.                                 }
  1539.                                 back[i].r.is_write=0;    // erreur, abandonner
  1540. #if HDEBUG
  1541.                                 printf("..error!\n");
  1542. #endif
  1543.                               }
  1544. #if HTS_WIN==0
  1545.                               else chmod(back[i].url_sav,HTS_ACCESS_FILE);      
  1546. #endif          
  1547.                             } else {  // on coupe tout!
  1548.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1549.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1550.                               }
  1551.                               back[i].status=0;  // terminΘ
  1552.                               if (!back[i].testmode)
  1553.                                 back[i].r.statuscode=-10;    // EUHH CANCEL
  1554.                               else
  1555.                                 back[i].r.statuscode=-10;    // "TEST OK"
  1556.                               if (back[i].r.soc!=INVALID_SOCKET) {
  1557. #if HTS_DEBUG_CLOSESOCK
  1558.                                 DEBUG_W("back_wait(3): deletehttp\n");
  1559. #endif
  1560.                                 deletehttp(&back[i].r);
  1561.                               }
  1562.                               back[i].r.soc=INVALID_SOCKET;
  1563.                             }
  1564.                           }
  1565.                         }
  1566.                       }
  1567.                     }
  1568.                   }
  1569.                 }
  1570.               }
  1571.             }
  1572. #endif              
  1573.  
  1574.             // rΘception de donnΘes depuis socket ou fichier
  1575.             if (back[i].status) {
  1576.               if (back[i].status==99)  // recevoir par bloc de lignes
  1577.                 retour_fread=http_xfread1(&(back[i].r),0);
  1578.               else if (back[i].status==98) { // recevoir longueur chunk en hexa caractΦre par caractΦre
  1579.                 // backuper pour lire dans le buffer chunk
  1580.                 htsblk r;
  1581.                 memcpy(&r, &(back[i].r), sizeof(htsblk));
  1582.                 back[i].r.is_write=0;                   // mΘmoire
  1583.                 back[i].r.adr=back[i].chunk_adr;        // adresse
  1584.                 back[i].r.size=back[i].chunk_size;      // taille taille chunk
  1585.                 back[i].r.totalsize=-1;                 // total inconnu
  1586.                 back[i].r.out=NULL;
  1587.                 back[i].r.is_file=0;
  1588.                 //
  1589.                 // ligne par ligne
  1590.                 retour_fread=http_xfread1(&(back[i].r),-1);
  1591.                 // modifier et restaurer
  1592.                 back[i].chunk_adr=back[i].r.adr;        // adresse
  1593.                 back[i].chunk_size=back[i].r.size;      // taille taille chunk
  1594.                 memcpy(&(back[i].r), &r, sizeof(htsblk));    // restaurer vΘritable r
  1595.               }
  1596.               else if (back[i].is_chunk) {         // attention chunk, limiter taille α lire
  1597. #if CHUNKDEBUG==1
  1598.                 printf("read %d bytes\n",(int)min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1599. #endif
  1600.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1601.               } else              
  1602.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) max_read_bytes);
  1603.                 // retour_fread=http_fread1(&(back[i].r));
  1604.             } else
  1605.               retour_fread=-1;                    // interruption ou annulation interne (peut ne pas Ωtre une erreur)
  1606.             
  1607.             // Si rΘception chunk, tester si on est pas α la fin!
  1608.             if (back[i].status==1) {
  1609.               if (back[i].is_chunk) {     // attendre prochain chunk
  1610.                 if (back[i].r.size==back[i].r.totalsize) {      // fin chunk!
  1611.                   //printf("chunk end at %d\n",back[i].r.size);
  1612.                   back[i].status=98;  // prochain chunk
  1613.                   if (back[i].chunk_adr!=NULL) { freet(back[i].chunk_adr); back[i].chunk_adr=NULL; } back[i].chunk_size=0;
  1614.                   retour_fread=0;       // pas d'erreur
  1615. #if CHUNKDEBUG==1
  1616.                   printf("waiting for next chunk header (soc %d)..\n",back[i].r.soc);
  1617. #endif
  1618.                 }
  1619.               }
  1620.             }
  1621.                           
  1622.             if (retour_fread < 0) {    // erreur rΘception
  1623.               back[i].status=0;    // terminΘ
  1624.               if (back[i].r.soc!=INVALID_SOCKET) {
  1625. #if HTS_DEBUG_CLOSESOCK
  1626.                 DEBUG_W("back_wait(4): deletehttp\n");
  1627. #endif
  1628.                 deletehttp(&back[i].r);
  1629.               }
  1630.               back[i].r.soc=INVALID_SOCKET;
  1631. #if CHUNKDEBUG==1
  1632.               if (back[i].is_chunk)
  1633.                 printf("must be the last chunk for %s (connection closed) - %d/%d\n",back[i].url_fil,back[i].r.size,back[i].r.totalsize);
  1634. #endif
  1635.               //if ((back[i].r.statuscode==-1) && (strnotempty(back[i].r.msg)==0)) {
  1636.               if ((back[i].r.statuscode<0) && (strnotempty(back[i].r.msg)==0)) {
  1637. #if HDEBUG
  1638.                 printf("error interruped: %s\n",back[i].r.adr);
  1639. #endif        
  1640.                 if (back[i].r.size>0)
  1641.                   strcatbuff(back[i].r.msg,"Interrupted transfer");
  1642.                 else
  1643.                   strcatbuff(back[i].r.msg,"No data (connection closed)");
  1644.                 back[i].r.statuscode=-4;
  1645.               }
  1646.  
  1647.               // finalize transfer
  1648.               if (back[i].r.statuscode>0) {
  1649.                 back_finalize(opt,cache,back,i);
  1650.               }
  1651.  
  1652.               if (back[i].r.totalsize>0) {    // tester totalsize
  1653.               //if ((back[i].r.totalsize>0) && (back[i].status==99)) {    // tester totalsize
  1654.                 if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1655.                   if (!opt->tolerant) {
  1656.                     //#if HTS_CL_IS_FATAL
  1657.                     if (back[i].r.adr) freet(back[i].r.adr); back[i].r.adr=NULL;
  1658.                     if (back[i].r.size<back[i].r.totalsize)
  1659.                       back[i].r.statuscode=-4;        // recatch
  1660.                     sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",(LLint)back[i].r.size,(LLint)back[i].r.totalsize);
  1661.                   } else {
  1662.                     //#else
  1663.                     // Un warning suffira..
  1664.                     if (cache->errlog!=NULL) {
  1665.                       fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1666.                     }
  1667.                     //#endif
  1668.                   }
  1669.                 }
  1670.               }
  1671. #if BDEBUG==1
  1672.               printf("transfer ok\n");
  1673. #endif
  1674.             } else if (retour_fread > 0) {    // pas d'erreur de rΘception et data
  1675.               if (back[i].timeout>0) {    // refresh timeout si besoin est
  1676.                 back[i].timeout_refresh=time_local();
  1677.               }
  1678.  
  1679.               // Traitement des en tΩtes chunks ou en tΩtes
  1680.               if (back[i].status==98) {        // rΘception taille chunk en hexa (  aprΦs les en tΩtes, peut ne pas
  1681.                 if (back[i].chunk_size>=2) {
  1682.                   int chunk_size=-1;
  1683.                   // Ωtre prΘsent)
  1684.                   if (back[i].chunk_adr[back[i].chunk_size-1]==10) {    // LF, fin ligne chunk
  1685.                     char chunk_data[64];
  1686.                     if (back[i].chunk_size<32) {      // pas trop gros
  1687.                       back[i].chunk_adr[ back[i].chunk_size-1]='\0';    // octet nul 
  1688.                       strcpybuff(chunk_data,"");    // hex number
  1689.                       strcatbuff(chunk_data,back[i].chunk_adr);
  1690. #if CHUNKDEBUG==1
  1691.                       printf("chunk received and read: %s\n",chunk_data);
  1692. #endif
  1693.                       if (back[i].r.totalsize<0)
  1694.                         back[i].r.totalsize=0;        // initialiser α 0
  1695.                       if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
  1696.                         back[i].r.totalsize+=chunk_size;    // noter taille
  1697.                         back[i].r.adr=(char*) realloct(back[i].r.adr,(INTsys) back[i].r.totalsize + 1);
  1698.                         if (!back[i].r.adr) {
  1699.                           if (cache->errlog!=NULL) {
  1700.                             fprintf(cache->errlog,"Error: Not enough memory ("LLintP") for %s%s"LF,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1701.                           }
  1702.                         }
  1703. #if CHUNKDEBUG==1
  1704.                         printf("chunk length: %d - next total "LLintP":\n",(int)chunk_size,(LLint)back[i].r.totalsize);
  1705. #endif
  1706.                       } else                                
  1707.                         if (cache->errlog!=NULL) {
  1708.                           fprintf(cache->errlog,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  1709.                         }
  1710.                     } else {                                  
  1711.                       if (cache->errlog!=NULL) {
  1712.                         fprintf(cache->errlog,"Warning: Chunk too big ("LLintP") for %s%s"LF,(LLint)back[i].chunk_size,back[i].url_adr,back[i].url_fil);
  1713.                       }
  1714.                     }
  1715.                     
  1716.                     // ok, continuer sur le body
  1717.                     
  1718.                     // si chunk non nul continuer (ou commencer)
  1719.                     if (chunk_size>0) {
  1720.                       back[i].status=1;     // continuer body    
  1721. #if CHUNKDEBUG==1
  1722.                       printf("waiting for body (chunk)\n");
  1723. #endif
  1724.                     } else {                // chunk nul, c'est la fin
  1725. #if CHUNKDEBUG==1
  1726.                       printf("chunk end, total: %d\n",back[i].r.size);
  1727. #endif
  1728.                       back[i].status=0;     // fin  
  1729.                       // finalize transfer
  1730.                       back_finalize(opt,cache,back,i);
  1731.                       if (back[i].r.soc!=INVALID_SOCKET) {
  1732. #if HTS_DEBUG_CLOSESOCK
  1733.                         DEBUG_W("back_wait(5): deletehttp\n");
  1734. #endif
  1735.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1736.  
  1737.                         /* Tester totalsize en fin de chunk */
  1738.                         if ((back[i].r.totalsize>0)) {    // tester totalsize
  1739.                           if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1740. #if HTS_CL_IS_FATAL
  1741.                             if (back[i].r.adr) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1742.                             back[i].r.statuscode=-1;
  1743.                             strcpybuff(back[i].r.msg,"Incorrect length");
  1744. #else
  1745.                             // Un warning suffira..
  1746.                             if (cache->errlog!=NULL) {
  1747.                               fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1748.                             }
  1749. #endif
  1750.                           }
  1751.                         }
  1752.                         
  1753.                       
  1754.                       }
  1755.                     }
  1756.  
  1757.                     // effacer buffer (chunk en tete)
  1758.                     if (back[i].chunk_adr!=NULL) {
  1759.                       freet(back[i].chunk_adr);
  1760.                       back[i].chunk_adr=NULL;
  1761.                       back[i].chunk_size=0;
  1762.                     }
  1763.                   
  1764.                   } // chunk LF?
  1765.                 }  // taille buffer chunk>2
  1766.                 //
  1767.               } else if (back[i].status==99) {        // en tΩtes (avant le chunk si il est prΘsent)
  1768.                 //
  1769.                 if (back[i].r.size>=2) {
  1770.                   // double LF
  1771.                   if (
  1772.                     ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) 
  1773.                     ||
  1774.                     (back[i].r.adr[0] == '<')    /* bogus server */
  1775.                     ) {
  1776.                     char rcvd[2048];
  1777.                     int ptr=0;
  1778.                     int noFreebuff=0;
  1779.                     
  1780. #if BDEBUG==1
  1781.                     printf("..ok, header received\n");
  1782. #endif
  1783.                     
  1784.                     /* Hack for zero-length headers */
  1785.                     if (back[i].r.adr[0] != '<') {
  1786.                       
  1787.                       // ----------------------------------------
  1788.                       // traiter en-tΩte!
  1789.                       // status-line α rΘcupΘrer
  1790.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  1791.                       if (strnotempty(rcvd)==0)
  1792.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1793.                       
  1794.                       // traiter status-line
  1795.                       treatfirstline(&back[i].r,rcvd);
  1796.                       
  1797. #if HDEBUG
  1798.                       printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
  1799. #endif
  1800.                       if (_DEBUG_HEAD) {
  1801.                         if (ioinfo) {
  1802.                           fprintf(ioinfo,"response for %s%s:\r\ncode=%d\r\n",jump_identification(back[i].url_adr),back[i].url_fil,back[i].r.statuscode);
  1803.                           fprintfio(ioinfo,back[i].r.adr,">>> ");
  1804.                           fprintf(ioinfo,"\r\n");
  1805.                           fflush(ioinfo);
  1806.                         }                    // en-tΩte
  1807.                       }
  1808.                       
  1809.                       // header // ** !attention! HTTP/0.9 non supportΘ
  1810.                       do {
  1811.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);          
  1812. #if HDEBUG
  1813.                         printf("(buffer)>%s\n",rcvd);      
  1814. #endif
  1815.                         /*
  1816.                         if (_DEBUG_HEAD) {
  1817.                         if (ioinfo) {
  1818.                         fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);      
  1819.                         fflush(ioinfo);
  1820.                         }
  1821.                         }
  1822.                         */
  1823.                         
  1824.                         if (strnotempty(rcvd))
  1825.                           treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd);  // traiter
  1826.                         
  1827.                         // parfois les serveurs buggΘs renvoient un content-range avec un 200
  1828.                         if (back[i].r.statuscode==200)  // 'OK'
  1829.                           if (strfield(rcvd,"content-range:"))  // Avec un content-range: relisez les RFC..
  1830.                             back[i].r.statuscode=206;    // FORCER A 206 !!!!!
  1831.                           
  1832.                       } while(strnotempty(rcvd));
  1833.                       // ----------------------------------------                    
  1834.  
  1835.                       // libΘrer mΘmoire  -- aprΦs! --
  1836.                       if (back[i].r.adr!=NULL) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1837.                     } else {
  1838.                       // assume text/html, OK
  1839.                       treatfirstline(&back[i].r, back[i].r.adr);
  1840.                       noFreebuff=1;
  1841.                     }
  1842.                       
  1843.                   
  1844.                     
  1845.                     /* 
  1846.                     Status code and header-response hacks
  1847.                     */
  1848.  
  1849.                     
  1850.                     // Check response : 203 == 200
  1851.                     if (back[i].r.statuscode==203) {  // 'Non-Authoritative Information'
  1852.                       back[i].r.statuscode=200;       // forcer "OK"
  1853.                     } else if (back[i].r.statuscode == 100) {
  1854.                       back[i].status=99;
  1855.                       back[i].r.size=0;
  1856.                       back[i].r.totalsize=0;
  1857.                       back[i].chunk_size=0;
  1858.                       back[i].r.statuscode=-1;
  1859.                       back[i].r.msg[0]='\0';
  1860.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  1861.                         fspc(opt->log,"debug"); fprintf(opt->log,"Status 100 detected for %s%s, continuing headers"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1862.                       }
  1863.                       continue;
  1864.                     }
  1865.                     
  1866.                     /*
  1867.                     Solve "false" 416 problems
  1868.                     */
  1869.                     if (back[i].r.statuscode==416) {  // 'Requested Range Not Satisfiable'
  1870.                       // Example:
  1871.                       // Range: bytes=2830-
  1872.                       // ->
  1873.                       // Content-Range: bytes */2830
  1874.                       if (back[i].range_req_size == back[i].r.crange) {
  1875.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1876.                         back[i].status=0;    // READY
  1877.                         back[i].r.size=back[i].r.totalsize=back[i].range_req_size;
  1878.                         filenote(back[i].url_sav,NULL);
  1879.                         back[i].r.statuscode=304;     // NOT MODIFIED
  1880.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  1881.                           fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (good 416 message), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1882.                         }
  1883.                       }
  1884.                     }
  1885.                     
  1886.                     // transform 406 into 200 ; we'll catch embedded links inside the choice page
  1887.                     if (back[i].r.statuscode==406) {  // 'Not Acceptable'
  1888.                       back[i].r.statuscode=200;
  1889.                     }
  1890.  
  1891.                     // Various hacks to limit re-transfers when updating a mirror
  1892.                     // Force update if same size detected
  1893.                     if (opt->sizehack) {
  1894.                       // We already have the file
  1895.                       // and ask the remote server for an update
  1896.                       // Some servers, especially dynamic pages severs, always
  1897.                       // answer that the page has been modified since last visit
  1898.                       // And answer with a 200 (OK) response, and the same page
  1899.                       // If the size is the same, and the option has been set, we assume
  1900.                       // that the file is identical - and therefore let's break the connection
  1901.                       if (back[i].is_update) {          // mise α jour
  1902.                         if (back[i].r.statuscode==200) {  // 'OK'
  1903.                           htsblk r = cache_read(opt,cache,back[i].url_adr,back[i].url_fil,NULL);    // lire entrΘe cache
  1904.                           if (r.statuscode == 200) {  // OK pas d'erreur cache
  1905.                             LLint len1,len2;
  1906.                             len1=r.totalsize;
  1907.                             len2=back[i].r.totalsize;
  1908.                             if (r.size>0)
  1909.                               len1=r.size;
  1910.                             if (len1>0) {
  1911.                               if (len1 == len2) {             // tailles identiques
  1912.                                 back[i].r.statuscode=304;     // forcer NOT MODIFIED
  1913.                                 deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1914.                                 if ((opt->debug>1) && (opt->log!=NULL)) {
  1915.                                   fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1916.                                 }
  1917.                               }
  1918.                             }
  1919.                           } else {
  1920.                             if (opt->errlog!=NULL) {
  1921.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"File seems complete (same size), but there was a cache read error: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1922.                             }
  1923.                           }
  1924.                           if (r.adr) {
  1925.                             freet(r.adr);
  1926.                           }
  1927.                         }
  1928.                       }
  1929.                     }
  1930.                     
  1931.                     // Various hacks to limit re-transfers when updating a mirror
  1932.                     // Detect already downloaded file (with another browser, for example)
  1933.                     if (opt->sizehack) {
  1934.                       if (!back[i].is_update) {          // mise α jour
  1935.                         if (back[i].r.statuscode==200) {  // 'OK'
  1936.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // not HTML
  1937.                             if (strnotempty(back[i].url_sav)) {  // target found
  1938.                               int size = fsize(back[i].url_sav);  // target size
  1939.                               if (size >= 0) {
  1940.                                 if (back[i].r.totalsize == size) {  // same size!
  1941.                                   deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1942.                                   back[i].status=0;    // READY
  1943.                                   back[i].r.size=back[i].r.totalsize;
  1944.                                   filenote(back[i].url_sav,NULL);
  1945.                                   back[i].r.statuscode=304;     // NOT MODIFIED
  1946.                                   if ((opt->debug>1) && (opt->log!=NULL)) {
  1947.                                     fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size file discovered), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1948.                                   }
  1949.                                 }
  1950.                               }
  1951.                             }
  1952.                           }
  1953.                         }
  1954.                       }
  1955.                     }
  1956.                     
  1957.                     // Various hacks to limit re-transfers when updating a mirror
  1958.                     // Detect bad range: header
  1959.                     if (opt->sizehack) {
  1960.                       // We have request for a partial file (with a 'Range: NNN-' header)
  1961.                       // and received a complete file notification (200), with 'Content-length: NNN'
  1962.                       // it might be possible that we had the complete file
  1963.                       // this is the case in *most* cases, so break the connection
  1964.                       if (back[i].r.is_write==0) {  // mode mΘmoire
  1965.                         if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1966.                           if (!back[i].testmode) {  // pas mode test
  1967.                             if (strnotempty(back[i].url_sav)) {
  1968.                               if (strcmp(back[i].url_fil,"/robots.txt")) {
  1969.                                 if (back[i].r.statuscode==200) {  // 'OK'
  1970.                                   if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1971.                                     if (back[i].r.statuscode==200) {      // "OK"
  1972.                                       if (back[i].range_req_size>0) {     // but Range: requested
  1973.                                         if (back[i].range_req_size == back[i].r.totalsize) {    // And same size
  1974. #if HTS_DEBUG_CLOSESOCK
  1975.                                           DEBUG_W("back_wait(skip_range): deletehttp\n");
  1976. #endif
  1977.                                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1978.                                           back[i].status=0;    // READY
  1979.                                           back[i].r.size=back[i].r.totalsize;
  1980.                                           filenote(back[i].url_sav,NULL);
  1981.                                           back[i].r.statuscode=304;     // NOT MODIFIED
  1982.                                           if ((opt->debug>1) && (opt->log!=NULL)) {
  1983.                                             fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (reget failed), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1984.                                           }
  1985.                                         }
  1986.                                       }
  1987.                                     }
  1988.                                     
  1989.                                   }
  1990.                                 }
  1991.                               }
  1992.                             }
  1993.                           }
  1994.                         }
  1995.                       }
  1996.                     }
  1997.                     // END - Various hacks to limit re-transfers when updating a mirror
  1998.  
  1999.                     /* 
  2000.                     End of status code and header-response hacks
  2001.                     */
  2002.  
  2003.                     
  2004.                     
  2005.                     /* Interdiction taille par le wizard? */
  2006.                     if (back[i].r.soc!=INVALID_SOCKET) {
  2007.                       if (!back_checksize(opt,&back[i],1)) {
  2008.                         back[i].status=0;  // FINI
  2009.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2010.                         if (!back[i].testmode)
  2011.                           strcpybuff(back[i].r.msg,"File too big");
  2012.                         else
  2013.                           strcpybuff(back[i].r.msg,"Test: File too big");
  2014.                       }
  2015.                     }
  2016.                     
  2017.                     /* sinon, continuer */
  2018.                     /* if (back[i].r.soc!=INVALID_SOCKET) {   // ok rΘcupΘrer body? */
  2019.                     // head: terminΘ
  2020.                     if (back[i].head_request) {
  2021.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2022.                         fspc(opt->log,"debug"); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2023.                       }
  2024. #if HTS_DEBUG_CLOSESOCK
  2025.                       DEBUG_W("back_wait(head request): deletehttp\n");
  2026. #endif
  2027.                       // Couper connexion
  2028.                       deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2029.                       back[i].status=0;  // terminΘ
  2030.                     }
  2031.                     // traiter une Θventuelle erreur 304 (cache α jour utilisable)
  2032.                     else if (back[i].r.statuscode==304) {  // document α jour dans le cache
  2033.                       // lire dans le cache
  2034.                       // ** NOTE: pas de vΘrif de la taille ici!!
  2035. #if HTS_DEBUG_CLOSESOCK
  2036.                       DEBUG_W("back_wait(file is not modified): deletehttp\n");
  2037. #endif
  2038.                       deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2039.                       back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  2040.                       if (!back[i].r.location)
  2041.                         back[i].r.location=back[i].location_buffer;
  2042.                       else {        /* recopier */
  2043.                         strcpybuff(back[i].location_buffer,back[i].r.location);
  2044.                         back[i].r.location=back[i].location_buffer;
  2045.                       }
  2046.  
  2047.                       // hack:
  2048.                       // In case of 'if-unmodified-since' hack, a 304 status can be sent
  2049.                       // then, force 'ok' status
  2050.                       if (back[i].r.statuscode == -1) {
  2051.                         if (fexist(back[i].url_sav)) {
  2052.                           back[i].r.statuscode=200;     // OK
  2053.                           if ((opt->debug>0) && (opt->log!=NULL)) {
  2054.                             fspc(opt->log,"debug"); fprintf(opt->log,"Not-modified status without cache guessed: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2055.                           }
  2056.                         }
  2057.                       }
  2058.  
  2059.                       // Status is okay?
  2060.                       if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
  2061.                         back[i].status=0;         // OK prΩt
  2062.                         back[i].r.notmodified=1;  // NON modifiΘ!
  2063.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  2064.                           fspc(opt->log,"debug"); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2065.                         }
  2066.  
  2067.                         // finalize
  2068.                         if (back[i].r.statuscode>0) {
  2069.                           back_finalize(opt,cache,back,i);
  2070.                         }
  2071.                         
  2072. #if DEBUGCA
  2073.                         printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
  2074. #endif
  2075.                         
  2076.                         //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  2077.                       } else {  // erreur
  2078.                         back[i].status=0;  // terminΘ
  2079.                         //printf("erreur cache\n");
  2080.                         
  2081.                       } 
  2082.                       
  2083.                     } else if ((back[i].r.statuscode==301)
  2084.                       || (back[i].r.statuscode==302)
  2085.                       || (back[i].r.statuscode==303)
  2086.                       || (back[i].r.statuscode==307)
  2087.                       || (back[i].r.statuscode==412)
  2088.                       || (back[i].r.statuscode==416)
  2089.                       ) {   // Ne pas prendre le html, erreurs connues et gΘrΘes
  2090. #if HTS_DEBUG_CLOSESOCK
  2091.                       DEBUG_W("back_wait(301,302,303,307,412,416..): deletehttp\n");
  2092. #endif
  2093.                       // Couper connexion
  2094.                       deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2095.                       back[i].status=0;  // terminΘ
  2096.                       // finalize
  2097.                       if (back[i].r.statuscode>0) {
  2098.                         back_finalize(opt,cache,back,i);
  2099.                       }
  2100.                     } else {    // il faut aller le chercher
  2101.                       
  2102.                       // effacer buffer (requΦte)
  2103.                       if (!noFreebuff) {
  2104.                         if (back[i].r.adr!=NULL) {
  2105.                           freet(back[i].r.adr);
  2106.                           back[i].r.adr=NULL;
  2107.                         }
  2108.                         back[i].r.size=0;
  2109.                       }
  2110.                       
  2111.                       // traiter 206 (partial content)
  2112.                       // xxc SI CHUNK VERIFIER QUE CA MARCHE??
  2113.                       if (back[i].r.statuscode==206) {  // on nous envoie un morceau (la fin) coz une partie sur disque!
  2114.                         LLint sz=fsize(back[i].url_sav);
  2115. #if HDEBUG
  2116.                         printf("partial content: "LLintP" on disk..\n",(LLint)sz);
  2117. #endif
  2118.                         if (sz>=0) {
  2119.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  2120.                             if (opt->getmode&2) {    // on peut ecrire des non html  **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
  2121.                               filenote(back[i].url_sav,NULL);    // noter fichier comme connu
  2122.                               back[i].r.out=fopen(fconv(back[i].url_sav),"ab");  // append
  2123.                               if (back[i].r.out) {
  2124.                                 back[i].r.is_write=1;    // Θcrire
  2125.                                 back[i].r.size=sz;    // dΘja Θcrit
  2126.                                 back[i].r.statuscode=200;  // Forcer 'OK'
  2127.                                 if (back[i].r.totalsize>0)
  2128.                                   back[i].r.totalsize+=sz;    // plus en fait
  2129.                                 fseek(back[i].r.out,0,SEEK_END);  // α la fin
  2130. #if HDEBUG
  2131.                                 printf("continue interrupted file\n");
  2132. #endif
  2133.                               } else {    // On est dans la m**
  2134.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2135.                                 strcpybuff(back[i].r.msg,"Can not open partial file");
  2136.                               }
  2137.                             }
  2138.                           } else {    // mΘmoire
  2139.                             FILE* fp=fopen(fconv(back[i].url_sav),"rb");
  2140.                             if (fp) {
  2141.                               LLint alloc_mem=sz + 1;
  2142.                               if (back[i].r.totalsize>0)
  2143.                                 alloc_mem+=back[i].r.totalsize;            // AJOUTER RESTANT!
  2144.                               if ( (back[i].r.adr=(char*) malloct((INTsys) alloc_mem)) ) {
  2145.                                 back[i].r.size=sz;
  2146.                                 if (back[i].r.totalsize>0)
  2147.                                   back[i].r.totalsize+=sz;    // plus en fait
  2148.                                 if (((int) fread(back[i].r.adr,1,(INTsys)sz,fp)) != sz) {
  2149.                                   back[i].status=0;  // terminΘ (voir plus loin)
  2150.                                   strcpybuff(back[i].r.msg,"Can not read partial file");
  2151.                                 } else {
  2152.                                   back[i].r.statuscode=200;  // Forcer 'OK'
  2153. #if HDEBUG
  2154.                                   printf("continue in mem interrupted file\n");
  2155. #endif
  2156.                                 }
  2157.                               } else {
  2158.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2159.                                 strcpybuff(back[i].r.msg,"No memory for partial file");
  2160.                               }
  2161.                               fclose(fp);
  2162.                             } else {  // Argh.. 
  2163.                               back[i].status=0;  // terminΘ (voir plus loin)
  2164.                               strcpybuff(back[i].r.msg,"Can not open partial file");
  2165.                             }
  2166.                           }
  2167.                         } else {    // Non trouvΘ??
  2168.                           back[i].status=0;  // terminΘ (voir plus loin)
  2169.                           strcpybuff(back[i].r.msg,"Can not find partial file");
  2170.                         }
  2171.                         // Erreur?
  2172.                         if (back[i].status==0) {
  2173.                           if (back[i].r.soc!=INVALID_SOCKET) {
  2174. #if HTS_DEBUG_CLOSESOCK
  2175.                             DEBUG_W("back_wait(206 solve problems): deletehttp\n");
  2176. #endif
  2177.                             deletehttp(&back[i].r);
  2178.                           }
  2179.                           back[i].r.soc=INVALID_SOCKET;
  2180.                           //back[i].r.statuscode=206;  ????????
  2181.                           back[i].r.statuscode=-5;
  2182.                           if (strnotempty(back[i].r.msg))
  2183.                             strcpybuff(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
  2184.                         }
  2185.                       }
  2186.                       
  2187.                       if (back[i].status!=0) {  // non terminΘ (erreur)
  2188.                         if (!back[i].testmode) {    // fichier normal
  2189.                           
  2190.                           if (back[i].r.empty && back[i].r.statuscode==200) {  // empty response
  2191.                             // Couper connexion
  2192.                             deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2193.                             back[i].status=0;  // terminΘ
  2194.                             if ( (back[i].r.adr=(char*) malloct((INTsys) 2)) ) {
  2195.                               back[i].r.adr[0] = 0;
  2196.                             }
  2197.                             back_finalize(opt,cache,back,i);
  2198.                           }
  2199.                           else if (!back[i].r.is_chunk) {    // pas de chunk
  2200.                             //if (back[i].r.http11!=2) {    // pas de chunk
  2201.                             back[i].is_chunk=0;
  2202.                             back[i].status=1;     // start body
  2203.                           } else {
  2204. #if CHUNKDEBUG==1
  2205.                             printf("chunk encoding detected %s..\n",back[i].url_fil);
  2206. #endif
  2207.                             back[i].is_chunk=1;
  2208.                             back[i].chunk_adr=NULL;
  2209.                             back[i].chunk_size=0;
  2210.                             back[i].status=98;    // start body wait chunk
  2211.                             back[i].r.totalsize=0;   /* devalidate size */
  2212.                           }
  2213.                           if (back[i].rateout>0) {
  2214.                             back[i].rateout_time=time_local();  // refresh pour transfer rate
  2215.                           }
  2216. #if HDEBUG
  2217.                           printf("(buffer) start body!\n");
  2218. #endif
  2219.                         } else {     // mode test, ne pas passer en 1!!
  2220.                           back[i].status=0;    // READY
  2221. #if HTS_DEBUG_CLOSESOCK
  2222.                           DEBUG_W("back_wait(test ok): deletehttp\n");
  2223. #endif
  2224.                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2225.                           if (back[i].r.statuscode==200) {
  2226.                             strcpybuff(back[i].r.msg,"Test: OK");
  2227.                             back[i].r.statuscode=-10;    // test rΘussi
  2228.                           }
  2229.                           else {    // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
  2230.                             char tempo[1000];
  2231.                             strcpybuff(tempo,back[i].r.msg);
  2232.                             strcpybuff(back[i].r.msg,"Test: ");
  2233.                             strcatbuff(back[i].r.msg,tempo);
  2234.                           }
  2235.                           
  2236.                         }
  2237.                       }
  2238.                       
  2239.                       } 
  2240.                       
  2241.                       /*}*/
  2242.                       
  2243.                   }  // si LF
  2244.                 }  // r.size>2
  2245.               }  // si == 99
  2246.               
  2247.             } // si pas d'erreurs
  2248. #if BDEBUG==1
  2249.             printf("bytes overall: %d\n",back[i].r.size);
  2250. #endif
  2251.           }  // donnΘes dispo
  2252.           
  2253.           // en cas d'erreur cl, supprimer Θventuel fichier sur disque
  2254. #if HTS_REMOVE_BAD_FILES
  2255.           if (back[i].status<0) {
  2256.             if (!back[i].testmode) {    // pas en test
  2257.               remove(back[i].url_sav);    // Θliminer fichier (endommagΘ)
  2258.               //printf("&& %s\n",back[i].url_sav);
  2259.             }
  2260.           }
  2261. #endif
  2262.  
  2263.           /* funny log for commandline users */
  2264.           //if (!opt->quiet) {  
  2265.           // petite animation
  2266.           if (opt->verbosedisplay==1) {
  2267.             if (back[i].status==0) {
  2268.               if (back[i].r.statuscode==200)
  2269.                 printf("* %s%s ("LLintP" bytes) - OK"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size);
  2270.               else
  2271.                 printf("* %s%s ("LLintP" bytes) - %d"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size,back[i].r.statuscode);
  2272.               fflush(stdout);
  2273.             }
  2274.           }
  2275.           //}
  2276.           
  2277.  
  2278.       } // status>0
  2279.     }  // for
  2280.     
  2281.     // vΘrifier timeouts
  2282.     if (gestion_timeout) {
  2283.       TStamp act;
  2284.       act=time_local();    // temps en secondes
  2285.       for(i=0;i<back_max;i++) {
  2286.         if (back[i].status>0) {  // rΘception/connexion/..
  2287.           if (back[i].timeout>0) {
  2288.             //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
  2289.             if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
  2290.               if (back[i].r.soc!=INVALID_SOCKET) {
  2291. #if HTS_DEBUG_CLOSESOCK
  2292.                 DEBUG_W("back_wait(timeout): deletehttp\n");
  2293. #endif
  2294.                 deletehttp(&back[i].r);
  2295.               }
  2296.               back[i].r.soc=INVALID_SOCKET;
  2297.               back[i].r.statuscode=-2;
  2298.               if (back[i].status==100)
  2299.                 strcpybuff(back[i].r.msg,"Connect Time Out");
  2300.               else if (back[i].status==101)
  2301.                 strcpybuff(back[i].r.msg,"DNS Time Out");
  2302.               else
  2303.                 strcpybuff(back[i].r.msg,"Receive Time Out");
  2304.               back[i].status=0;  // terminΘ
  2305.             } else if ((back[i].rateout>0) && (back[i].status<99)) {
  2306.               if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) {   // checker au bout de 15s
  2307.                 if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) {  // trop lent
  2308.                   back[i].status=0;  // terminΘ
  2309.                   if (back[i].r.soc!=INVALID_SOCKET) {
  2310. #if HTS_DEBUG_CLOSESOCK
  2311.                     DEBUG_W("back_wait(rateout): deletehttp\n");
  2312. #endif
  2313.                     deletehttp(&back[i].r);
  2314.                   }
  2315.                   back[i].r.soc=INVALID_SOCKET;
  2316.                   back[i].r.statuscode=-3;
  2317.                   strcpybuff(back[i].r.msg,"Transfer Rate Too Low");
  2318.                 }
  2319.               }
  2320.             }
  2321.           }
  2322.         }
  2323.       }
  2324.     }
  2325.     max_loop--;
  2326. #if HTS_ANALYSTE
  2327.     max_loop_chk++;
  2328. #endif
  2329.   } while((busy_state) && (busy_recv) && (max_loop>0));
  2330. #if HTS_ANALYSTE
  2331.   if ((!busy_recv) && (!busy_state)) {
  2332.     if (max_loop_chk>=1) {
  2333.       Sleep(10);    // un tite pause pour Θviter les lag..
  2334.     }
  2335.   }
  2336. #endif
  2337. }
  2338.  
  2339. int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
  2340.   LLint size_to_test;
  2341.   if (check_only_totalsize)
  2342.     size_to_test=eback->r.totalsize;
  2343.   else
  2344.     size_to_test=max(eback->r.totalsize,eback->r.size);
  2345.   if (size_to_test>=0) {
  2346.     
  2347.     /* Interdiction taille par le wizard? */
  2348.     if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,(eback->r.totalsize+1023)/1024)==-1) {
  2349.       return 0;     /* interdit */
  2350.     }                     
  2351.     
  2352.     /* vΘrifier taille classique (heml et non html) */
  2353.     if ((istoobig(size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
  2354.       return 0;     /* interdit */
  2355.     }
  2356.   }
  2357.   return 1;
  2358. }
  2359.  
  2360.  
  2361. // octets transfΘrΘs + add
  2362. LLint back_transfered(LLint nb,lien_back* back,int back_max) {
  2363.   int i;
  2364.   // ajouter octets en instance
  2365.   for(i=0;i<back_max;i++)
  2366.     if ((back[i].status>0) && (back[i].status<99))
  2367.       nb+=back[i].r.size;
  2368.   return nb;      
  2369. }
  2370.  
  2371. // infos backing
  2372. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2373. void back_info(lien_back* back,int i,int j,FILE* fp) {
  2374.   if (back[i].status>=0) {
  2375.     char s[256]; 
  2376.     s[0]='\0';
  2377.     back_infostr(back,i,j,s);
  2378.     strcatbuff(s,LF);
  2379.     fprintf(fp,"%s",s);
  2380.   }
  2381. }
  2382.  
  2383. // infos backing
  2384. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2385. void back_infostr(lien_back* back,int i,int j,char* s) {
  2386.   if (back[i].status>=0) {
  2387.     int aff=0;
  2388.     if (j & 1) {
  2389.       if (back[i].status==100) {
  2390.         strcatbuff(s,"CONNECT ");
  2391.       } else if (back[i].status==99) {
  2392.         strcatbuff(s,"INFOS ");
  2393.         aff=1;
  2394.       } else if (back[i].status==98) {
  2395.         strcatbuff(s,"INFOSC");             // infos chunk
  2396.         aff=1;
  2397.       }
  2398.       else if (back[i].status>0) {
  2399. #if HTS_ANALYSTE==2
  2400.         strcatbuff(s,"WAIT ");
  2401. #else
  2402.         strcatbuff(s,"RECEIVE "); 
  2403. #endif
  2404.         aff=1; 
  2405.       }
  2406.     } 
  2407.     if (j & 2) {
  2408.       if (back[i].status==0) {
  2409.         switch (back[i].r.statuscode) {
  2410.         case 200:
  2411.           strcatbuff(s,"READY ");
  2412.           aff=1;
  2413.           break;
  2414. #if HTS_ANALYSTE==2
  2415.         default:
  2416.           strcatbuff(s,"ERROR ");
  2417.           break;
  2418. #else
  2419.         case -1:
  2420.           strcatbuff(s,"ERROR ");
  2421.           aff=1;
  2422.           break;
  2423.         case -2:
  2424.           strcatbuff(s,"TIMEOUT ");
  2425.           aff=1;
  2426.           break;
  2427.         case -3:
  2428.           strcatbuff(s,"TOOSLOW ");
  2429.           aff=1;
  2430.           break;
  2431.         case 400:
  2432.           strcatbuff(s,"BADREQUEST ");
  2433.           aff=1;
  2434.           break;
  2435.         case 401: case 403:
  2436.           strcatbuff(s,"FORBIDDEN ");
  2437.           aff=1;
  2438.           break;
  2439.         case 404:
  2440.           strcatbuff(s,"NOT FOUND ");
  2441.           aff=1;
  2442.           break;
  2443.         case 500:
  2444.           strcatbuff(s,"SERVERROR ");
  2445.           aff=1;
  2446.           break;
  2447.         default:
  2448.           {
  2449.             char s2[256];
  2450.             sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
  2451.             strcatbuff(s,s2);
  2452.           }
  2453.           aff=1;
  2454. #endif
  2455.         }
  2456.       }
  2457.     }
  2458.     
  2459.     if (aff) {
  2460.       {
  2461.         char s2[1024];
  2462.         sprintf(s2,"\"%s",back[i].url_adr); strcatbuff(s,s2);
  2463.         
  2464.         if (back[i].url_fil[0]!='/') strcatbuff(s,"/");
  2465.         sprintf(s2,"%s\" ",back[i].url_fil); strcatbuff(s,s2);
  2466.         sprintf(s,LLintP" "LLintP" ",(LLint)back[i].r.size,(LLint)back[i].r.totalsize); strcatbuff(s,s2);
  2467.       }
  2468.     }
  2469.   }
  2470. }
  2471.  
  2472. // -- backing --
  2473.  
  2474. #undef test_flush
  2475.